#include "ResourceManager.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QtConcurrent>
#include <QFile>
#include <QDir>
#include <QProcess>
#include <QTimer>
#include "glog/logging.h"

void CResourceManager::Upgrade(QString filename)
{
	QtConcurrent::run([=]() {
		auto ret = QProcess::execute(QString("msiexec.exe /i %1 /qn ").arg(filename));
		emit installFinished();
	});
}

void CResourceManager::LoadResource(int32_t type, QString url)
{
	if (url.isEmpty())
	{
		return;
	}

	download_resource(type, url);
}

QString CResourceManager::GetUrlFilename(const QString & url)
{
	return get_url_file_name(url);
}

void CResourceManager::download_resource(int type, const QString& url)
{
	QString filename = get_url_file_name(url);
	QString filepath = QString("./cache/ad/%1").arg(filename);
	if (check_local_cache_file(filename))
	{
		emit resourceDownloadFinished(type, true, filepath);
		return;
	}

	auto obj = new CResDownloadObj(type, url, filepath);

	connect(obj, &CResDownloadObj::downloadProgress, this, [&](int type, qint64 cur, qint64 total) {
		emit resourceDownloadProgress(type, cur, total);
	}, Qt::QueuedConnection);
	connect(obj, &CResDownloadObj::downloadFinished, this, [&](int id, bool flag, QString filepath) {
		emit resourceDownloadFinished(id, flag, filepath);
	}, Qt::QueuedConnection);

}

QString CResourceManager::get_url_file_name(const QString & url)
{
	QStringList sl = url.split('/');
	if (sl.isEmpty())
	{
		return "";
	}

	return sl.last();
}

bool CResourceManager::check_local_cache_file(const QString & filename)
{
	QDir dir("./cache/ad/");
	auto l = dir.entryInfoList(QDir::Files);

	foreach(const QFileInfo fi, l)
	{
		if (fi.fileName() == filename)
		{
			return true;
		}
	}

	return false;
}

CResDownloadObj::CResDownloadObj(int id, const QString & url, const QString & filepath)
	:filepath_(filepath)
	, url_(url)
	, id_(id)
{
	LOG(INFO) << "new res download obj: " << id << " " << url.toStdString();
	// open file
	file_ = new QFile(filepath + ".tmp");
	if (!file_->open(QIODevice::WriteOnly))
	{
		emit downloadFinished(id_, false, filepath_);
		return;
	}

	// init network access manager
	auto net = new QNetworkAccessManager(this);
	// send req
	QNetworkRequest req;
	req.setUrl(url);
	auto reply = net->get(req);
	if (reply == Q_NULLPTR)
	{
		LOG(ERROR) << "create res download obj request failed";
		emit downloadFinished(id_, false, filepath_);
		deleteLater();
		return;
	}

	connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(event_net_error(QNetworkReply::NetworkError)));
	connect(reply, &QNetworkReply::finished, this, &CResDownloadObj::event_net_finished);
	connect(reply, &QNetworkReply::readyRead, this, &CResDownloadObj::event_net_ready_read);
	connect(reply, &QNetworkReply::downloadProgress, this, [&](qint64 cur, qint64 total) {
		emit downloadProgress(id_, cur, total);
	});
}

CResDownloadObj::~CResDownloadObj()
{
	LOG(INFO) << "release res download obj: " << url_.toStdString();
	if (file_ != Q_NULLPTR)
	{
		file_->close();
	}

	delete file_;
}

void CResDownloadObj::event_net_error(QNetworkReply::NetworkError code)
{
	LOG(ERROR) << "res download obj net error: " << code;
	if (file_ != Q_NULLPTR && file_->isOpen())
	{
		file_->close();
	}

	emit downloadFinished(id_, false, filepath_);
	deleteLater();
}

void CResDownloadObj::event_net_finished()
{
	if (file_ == Q_NULLPTR || !file_->isWritable())
	{
		emit downloadFinished(id_, false, filepath_);
		deleteLater();
		return;
	}

	file_->rename(filepath_);
	file_->close();

	emit downloadFinished(id_, true, filepath_);
	deleteLater();
}

void CResDownloadObj::event_net_ready_read()
{
	if (file_ == Q_NULLPTR || !file_->isWritable())
	{
		return;
	}

	QNetworkReply* res = qobject_cast<QNetworkReply*>(sender());
	if (res == Q_NULLPTR)
	{
		return;
	}

	file_->write(res->readAll());
}
